package com.duqc.quartz;

import com.duqc.response.ResultException;
import com.duqc.util.CommonUtil;
import com.duqc.util.DateUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @ClassName JobUtil
 * @Description JobUtil
 * @Author duqc
 * @Date 2021/9/7
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class JobUtil {

    private final Scheduler scheduler;

//    private final ScheduleJobDAO scheduleJobDAO;

    /**
     * 新增任务
     * 超时策略说明（SimpleTrigger）：
     * MISFIRE_INSTRUCTION_FIRE_NOW：指示调度引擎在MisFire的情况下，将任务(JOB)马上执行一次
     * MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT：指示调度引擎重新调度该任务，repeat count保持不变，
     * 并且服从trigger定义时的endTime,如果现在的时间，如果当前时间已经晚于 end-time，那么这个触发器将不会在被激发。（从恢复时间立即执行）
     * MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT：这个策略跟上面的2策略一样，唯一的区别就是设置触发器的时间
     * 不是“现在” 而是下一个 scheduled time。
     * MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT：指示调度引擎重新调度该任务，repeat count 是剩余应该执行的次数，
     * 也就是说本来这个任务应该执行10次，但是已经错过了3次，那么这个任务就还会执行7次。
     * MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT：这个策略与上面的策略3比较类似，区别就是repeat count
     * 是剩余应该执行的次数而不是全部的执行次数
     * MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY：这个策略是忽略所有的超时状态
     *
     * @param job
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveTask(ScheduleJob job) {
        /*
         * 1.将任务记录插入到t_schedule_job 2.将任务交由Scheduler安排触发
         */
        try {
            job.setTriggerName("trigger" + job.getJobName());
            job.setTriggerGroup(job.getJobGroup());
            job.setJobState(0);
            job.setCreateTime(DateUtils.getNow());
            job.setRowGuid(CommonUtil.uuidString());
//            this.scheduleJobDAO.insert(job);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
            throw new ResultException("新增任务失败");
        }
        try {
            //构建job信息（这里可以动态配置）
            JobDetail jobDetail = JobBuilder.newJob(SchedulerJob.class).withIdentity(job.getJobName(), job.getJobGroup())
                    .withDescription(job.getJobRemark()).build();

            //触发时间点
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(job.getTriggerName(), job.getTriggerGroup())
                    //开始时间
                    .startAt(DateUtils.parseDate(job.getStartTime(), "yyyy-MM-dd HH:mm:ss"))
                    //结束时间
                    .endAt(DateUtils.parseDate(job.getEndTime(), "yyyy-MM-dd HH:mm:ss"))
                    .withSchedule(SimpleScheduleBuilder.simpleSchedule().withMisfireHandlingInstructionNowWithExistingCount()
                            //每...执行一次
                            .withIntervalInSeconds(3)
                            .repeatForever())
                    .build();

            //传递的参数
            jobDetail.getJobDataMap().put("rowGuid", "111111");
            //交由Scheduler安排触发
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
            throw new ResultException("新增任务失败");
        }
    }

    /**
     * 删除任务
     *
     * @param jobName  jobName
     * @param jobGroup jobGroup
     */
    @Transactional(rollbackFor = Exception.class)
    public void remove(String jobName, String jobGroup) {
        //通过个job可以绑定多个trigger 由多个触发器来执行job任务
        try {
            scheduler.deleteJob(JobKey.jobKey(jobName, jobGroup));
        } catch (Exception e) {
            log.info(e.getMessage(), e);
            throw new ResultException("移除任务失败");
        }
    }

    /**
     * 获取Job状态
     *
     * @param name  jobName
     * @param group jobGroup
     */
    public String getJobState(String name, String group) {
        TriggerKey triggerKey = TriggerKey.triggerKey(name, group);
        try {
            Trigger trigger = scheduler.getTrigger(triggerKey);
            return scheduler.getTriggerState(triggerKey).name();
        } catch (SchedulerException e) {
            log.info(e.getMessage(), e);
            throw new ResultException("获取Job状态失败");
        }
    }

    /**
     * 暂停任务
     *
     * @param jobName  jobName
     * @param jobGroup jobGroup
     */
    public void pauseJob(String jobName, String jobGroup) {
        try {
            JobKey jobKey = new JobKey(jobName, jobGroup);
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            if (null == jobDetail) {
                throw new ResultException("当前任务不存在");
            }
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * 恢复任务
     *
     * @param jobName  jobName
     * @param jobGroup jobGroup
     */
    public void resumeJob(String jobName, String jobGroup) {
        try {
            JobKey jobKey = new JobKey(jobName, jobGroup);
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            if (null == jobDetail) {
                throw new ResultException("当前任务不存在");
            }
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}
